import voice
import datetime
from clock_setting import ClockSettings
import bisect
import time
from threading import Thread
# from pydantic import BaseModel


def get_time():
    now = datetime.datetime.now()
    return [now.hour, now.minute]



class Clock:
    def __init__(self, settings: ClockSettings=None) -> None:
        # self.slient_hours=set(settings.silentHours)
        # self.report_minutes=set(settings.reportMinutes)
        # self.template=settings.reportTemplate
        # self.bell_time=settings.bellRepeatTime
        # self.check_peri
        self.settings=settings
        if not settings:
            settings=ClockSettings()
        self.update_settings(settings)
        hr, min = get_time()
        self.ringBell()
        self.reportTime(hr, min)
        self.last_alarm_time = [hr, min]

    def update_settings(self, settings: ClockSettings):
        self.settings=settings
        self.template = settings.reportTemplate
        self.bell_times=settings.bellRepeatTime
        self.alarm_minutes=settings.reportMinutes
        self.check_period=settings.checkPeriod
        self.alarm_hours=[]
        for i in range(24):
            if i not in settings.silentHours:
                self.alarm_hours.append(i)


    def ringBell(self, force=True):
        voice.ring_bell(self.bell_times)

    def reportTime(self, hour: int, minute: int, force=True):
        text = self.template.format(hour=hour, minute=minute)
        voice.say(text)

    def next_alarm_time(self):
        h,m=get_time()
        hid = bisect.bisect_left(self.alarm_hours,h)
        mid=bisect.bisect_left(self.alarm_minutes,m)
        if mid==len(self.alarm_minutes):
            mid=0
            hid+=1
        hid%=len(self.alarm_hours)
        return [self.alarm_hours[hid],self.alarm_minutes[mid]]

    def alarm(self):
        h,m=get_time()
        self.ringBell()
        self.reportTime(h,m)
        self.last_alarm_time=[h,m]

    def alarm_test(self,hour: int=None, minute: int=None):
        if not hour:
            hour,minute=get_time()
        self.ringBell()
        self.reportTime(hour,minute)

    def run(self):
        h,m=get_time()
        if [h,m]==self.last_alarm_time:
            time.sleep(self.check_period)
            self.run()
        elif h in self.alarm_hours and m in self.alarm_minutes:
            self.alarm()
            time.sleep(self.check_period)
            self.run()

    def run_async(self):
        thread=Thread(target=self.run)
        thread.start()

if __name__ == '__main__':
    clock=Clock(ClockSettings())
    print(clock.next_alarm_time())
    clock.alarm_test()
